﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint.Administration;
using System.ComponentModel;
using System.Web.UI;
using System.IO;
using System.Runtime.CompilerServices;
using System.Collections;
using Microsoft.Scripting.Runtime;

namespace IronSharePoint.Web.WebControls
{
    public class IronBaseWebPart : WebPart, IIronRenderProvider, IWebActionable
    {
        protected ControlCollection baseControls;
        protected ControlCollection customControls;

        [WebBrowsable(true)]
        [Personalizable(PersonalizationScope.Shared)]
        public string FeatureId { get; set; }

        [WebBrowsable(true)]
        [Personalizable(PersonalizationScope.Shared)]
        public string ScriptPath { get; set; }

        [WebBrowsable(false)]
        [Personalizable(PersonalizationScope.Shared | PersonalizationScope.User)]
        public string Data{ get; set; }


        [WebBrowsable(true)]
        [Personalizable(PersonalizationScope.Shared)]
        [WebDisplayName("Enable Ajax")]
        [Category("Ajax")]
        public bool AjaxEnabled { get; set; }

        [WebBrowsable(true)]
        [Personalizable(PersonalizationScope.Shared)]
        [WebDisplayName("Progress template")]
        [Category("Ajax")]
        public string AjaxProgressTemplate { get; set; }

        [WebBrowsable(true)]
        [Personalizable(PersonalizationScope.Shared)]
        [WebDisplayName("Dynamic layout")]
        [Category("Ajax")]
        public bool AjaxProgressDynamicLayout { get; set; }

        [WebBrowsable(true)]
        [Personalizable(PersonalizationScope.Shared)]
        [WebDisplayName("Display progress after")]
        [Category("Ajax")]
        public int AjaxProgressDisplayAfter { get; set; }

        [WebBrowsable(true)]
        [Personalizable(PersonalizationScope.Shared)]
        [WebDisplayName("Refresh interval")]
        [Category("Ajax")]
        public int AjaxAutoRefreshInterval { get; set; }

        [WebBrowsable(true)]
        [Personalizable(PersonalizationScope.Shared)]
        [WebDisplayName("Enable jQuery")]
        [Category("jQuery")]
        public bool JQueryEnabled { get; set; }

        protected IronScriptEngine engine;
        protected UpdatePanel updatePanel = null;
        protected UpdateProgress updateProgress = null;
        protected Timer timer = null;
        protected Exception exception = null;
        protected IronDynamicRenderControl dynamicRenderControl=null;

        protected Dictionary<string,object> dynamicAttributes;


        public IronBaseWebPart()
        {
            AjaxEnabled = false;
            AjaxAutoRefreshInterval = 0;
            AjaxProgressDisplayAfter = 2000;
            AjaxProgressDynamicLayout = true;
            AjaxProgressTemplate = IronConstant.AjaxProgressTemplate;

            this.ExportMode = WebPartExportMode.NonSensitiveData;

            dynamicAttributes = new Dictionary<string, object>();
        }

        [SpecialName]
        public object GetBoundMember(string name)
        {
            if (dynamicAttributes.ContainsKey(name) == false)
            {
                throw new MissingMemberException("Attibute " + name + " not found.");
            }

            return dynamicAttributes[name];
        }

        [SpecialName]
        public void SetMemberAfter(string name, object value)
        {
            if (dynamicAttributes.ContainsKey(name))
            {
                dynamicAttributes[name] = value;
            }
            else
            {
                dynamicAttributes.Add(name, value);
            }
        }

        [SpecialName]
        public void DeleteMember(string name)
        {
            if (dynamicAttributes.ContainsKey(name) == false)
            {
                throw new MissingMemberException("Attibute " + name + " not found.");
            }

            dynamicAttributes.Remove(name);

        }

        [SpecialName]
        public IEnumerable GetMemberNames()
        {
            return dynamicAttributes.Keys;
        }

        protected override void OnInit(EventArgs e)
        {
            
            try
            {
                if (Page.Request["skipIron"] != null && Page.Request["skipIron"] == "true" && SPFarm.Local.CurrentUserIsAdministrator())
                    throw new Exception("skip Iron");

                engine = new IronScriptEngine();

                EnsureScriptManager();
                EnsureUpdatePanelFixups();

                if (JQueryEnabled && this.Page != null)
                    this.Page.ClientScript.RegisterClientScriptInclude("jquery-1.3.2", "/_layouts/IronSharePoint/jquery-1.3.2.min.js");        

                engine.ScriptResolver.FeatureId = new Guid(FeatureId);
                engine.CompileScriptFrom(ScriptPath);

                engine.Scope.SetVariable("self", this);

                if (engine!=null && engine.Scope.ContainsVariable("OnInit"))
                {
                    object method = engine.Scope.GetVariable("OnInit");
                    engine.Operations.Call(method, e);
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            base.OnInit(e);
        }

        protected override void OnLoad(EventArgs e)
        {
            if (exception != null)
                return;

            try
            {
                if (engine!=null && engine.Scope.ContainsVariable("OnLoad"))
                {
                    object method = engine.Scope.GetVariable("OnLoad");
                    engine.Operations.Call(method, e);
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            base.OnLoad(e);
        }

        public override ControlCollection Controls
        {
            get
            {
                if (baseControls == null)
                    baseControls = base.Controls;

                if (customControls != null)
                    return customControls;

                return baseControls;
            }
        }

        public override EditorPartCollection CreateEditorParts()
        {
            if (exception != null)
                return base.CreateEditorParts();

            try
            {
                if (engine!=null && engine.Scope.ContainsVariable("CreateEditorParts"))
                {
                    object method = engine.Scope.GetVariable("CreateEditorParts");
                    ICollection customEditors = (ICollection)engine.Operations.Call(method);

                    int i = 0;
                    foreach(object o in customEditors)
                    {
                        EditorPart editor = o as EditorPart;
                        if (editor != null)
                        {
                            editor.ID = this.ID + customEditors + "_" + (++i).ToString();
                        }
                    }

                    return new EditorPartCollection(base.CreateEditorParts(), customEditors);
                }
               
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            return base.CreateEditorParts();
        }

        protected override void CreateChildControls()
        {
            if (exception != null)
                return;

            try
            {
                if (AjaxEnabled)
                {
                    if (updatePanel == null)
                    {

                        updatePanel = new UpdatePanel();

                        if (String.IsNullOrEmpty(AjaxProgressTemplate) == false)
                        {
                            updateProgress = new UpdateProgress();
                            updateProgress.ID = "updateProgress";
                            updateProgress.DynamicLayout = AjaxProgressDynamicLayout;
                            updateProgress.AssociatedUpdatePanelID = updatePanel.ClientID;
                            updateProgress.ProgressTemplate = new IronDynamicTemplate(AjaxProgressTemplate);
                            updateProgress.DisplayAfter = AjaxProgressDisplayAfter;
                            Controls.Add(updateProgress);
                        }

                        if (AjaxAutoRefreshInterval > 0)
                        {
                            timer = new Timer();
                            timer.Interval = AjaxAutoRefreshInterval;
                            //timer.Tick += new EventHandler<EventArgs>(powerControl.AjaxAutoRefreshIntervalElapsed);
                            updatePanel.ContentTemplateContainer.Controls.Add(timer);
                        }

                        Controls.Add(updatePanel);
                        dynamicRenderControl = new IronDynamicRenderControl(this);
                        updatePanel.ContentTemplateContainer.Controls.Add(dynamicRenderControl);

                        customControls = dynamicRenderControl.Controls;
                    }
                    

                }

                if (engine!=null && engine.Scope.ContainsVariable("CreateChildControls"))
                {
                    object method = engine.Scope.GetVariable("CreateChildControls");
                    engine.Operations.Call(method);
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            base.CreateChildControls();
        }


        protected override void OnPreRender(EventArgs e)
        {
            if (exception != null)
                return;

            try
            {
                if (engine!=null && engine.Scope.ContainsVariable("OnPreRender"))
                {
                    object method = engine.Scope.GetVariable("OnPreRender");
                    engine.Operations.Call(method, e);
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            base.OnPreRender(e);
        }

        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            if(exception==null)
            {
                try
                {
                    if (engine!=null && engine.Scope.ContainsVariable("Render") && AjaxEnabled == false)
                    {
                        object method = engine.Scope.GetVariable("Render");
                        engine.Operations.Call(method, writer);
                    }
                    else
                    {
                        foreach (Control ctrl in Controls)
                        {
                            ctrl.RenderControl(writer);
                        }
                    }
                }
                catch (Exception ex)
                {
                    exception = ex;
                }
            }

            if (exception != null)
            {
                writer.Write("<h3>" + exception.Message + "</h3>");
                
                if (SPFarm.Local.CurrentUserIsAdministrator())
                {
                    writer.Write("<br/>");
                    writer.Write(exception.StackTrace);
                }
            }

        }

        public void RenderContent(HtmlTextWriter writer)
        {
            if (engine!=null && engine.Scope.ContainsVariable("Render"))
            {
                object method = engine.Scope.GetVariable("Render");
                engine.Operations.Call(method, writer);
            }
            else
            {
                foreach (Control ctrl in Controls)
                {
                    ctrl.RenderControl(writer);
                }
            }
        }



        protected override void OnUnload(EventArgs e)
        {

            if (exception != null)
                return;

            if (engine!=null && engine.Scope.ContainsVariable("OnUnload"))
            {
                object method = engine.Scope.GetVariable("OnUnload");
                engine.Operations.Call(method ,e);
            }

            base.OnUnload(e);
        }

        #region Ajax Fixes

        protected void EnsureScriptManager()
        {
            ScriptManager scriptManager = ScriptManager.GetCurrent(this.Page);
            if (scriptManager == null)
            {
                scriptManager = new ScriptManager();
                scriptManager.EnablePartialRendering = true;
                if (Page.Form != null)
                {
                    Page.Form.Controls.AddAt(0, scriptManager);
                }
            }
        }

        protected void EnsureUpdatePanelFixups()
        {
            if (this.Page.Form != null)
            {
                string formOnSubmitAtt = this.Page.Form.Attributes["onsubmit"];
                if (formOnSubmitAtt == "return _spFormOnSubmitWrapper();")
                {
                    this.Page.Form.Attributes["onsubmit"] = "_spFormOnSubmitWrapper();";
                }
            }
            ScriptManager.RegisterStartupScript(this, typeof(IronBaseWebPart), "UpdatePanelFixup", "_spOriginalFormAction = document.forms[0].action; _spSuppressFormOnSubmitWrapper=true;", true);
        }

        #endregion

        #region WebPart Connection Providers

        [ConnectionProvider("Field","ironFieldProvider")]
        public IWebPartField GetFieldProvider()
        {
            if (exception != null)
                return null;

            IWebPartField provider = null;

            try
            {
                if (engine!=null && engine.Scope.ContainsVariable("GetFieldProvider"))
                {
                    object method = engine.Scope.GetVariable("GetFieldProvider");
                    provider = engine.Operations.Call(method) as IWebPartField;
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            return provider;
        }

        [ConnectionProvider("Row", "ironRowProvider")]
        public IWebPartRow GetRowProvider()
        {
            if (exception != null)
                return null;

            IWebPartRow provider = null;

            try
            {
                if (engine!=null && engine.Scope.ContainsVariable("GetRowProvider"))
                {
                    object method = engine.Scope.GetVariable("GetRowProvider");
                    provider = engine.Operations.Call(method) as IWebPartRow;
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            return provider;
        }

        [ConnectionProvider("Table", "ironTableProvider")]
        public IWebPartTable GetTableProvider()
        {
            if (exception != null)
                return null;

            IWebPartTable provider = null;

            try
            {
                if (engine!=null && engine.Scope.ContainsVariable("GetTableProvider"))
                {
                    object method = engine.Scope.GetVariable("GetTableProvider");
                    provider = engine.Operations.Call(method) as IWebPartTable;
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            return provider;
        }

        [ConnectionProvider("Parameters", "ironParametersProvider")]
        public IWebPartParameters GetParametersProvider()
        {
            if (exception != null)
                return null;

            IWebPartParameters provider = null;

            try
            {
                if (engine!=null && engine.Scope.ContainsVariable("GetParametersProvider"))
                {
                    object method = engine.Scope.GetVariable("GetParametersProvider");
                    provider = engine.Operations.Call(method) as IWebPartParameters;
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            return provider;
        }

        #endregion

        #region WebPart Connection Consumers

        [ConnectionConsumer("Field", "ironFieldConsumer")]
        public void SetFieldProvider(IWebPartField provider)
        {
            if (exception != null)
                return;

            try
            {
                if (engine!=null && engine.Scope.ContainsVariable("SetFieldProvider"))
                {
                    object method = engine.Scope.GetVariable("SetFieldProvider");
                    engine.Operations.Call(method, provider);
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

        }

        [ConnectionConsumer("Row", "ironRowConsumer")]
        public void SetRowProvider(IWebPartRow provider)
        {
            if (exception != null)
                return;


            try
            {
                if (engine!=null && engine.Scope.ContainsVariable("SetRowProvider"))
                {
                    object method = engine.Scope.GetVariable("SetRowProvider");
                    engine.Operations.Call(method, provider);
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

        }

        [ConnectionConsumer("Table", "ironTableConsumer")]
        public void SetTableProvider(IWebPartRow provider)
        {
            if (exception != null)
                return;


            try
            {
                if (engine!=null && engine.Scope.ContainsVariable("SetTableProvider"))
                {
                    object method = engine.Scope.GetVariable("SetTableProvider");
                    engine.Operations.Call(method, provider);
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

        }

        [ConnectionConsumer("Parameters", "ironParametersConsumer")]
        public void SetParametersProvider(IWebPartParameters provider)
        {
            if (exception != null)
                return;


            try
            {
                if (engine!=null && engine.Scope.ContainsVariable("SetParametersProvider"))
                {
                    object method = engine.Scope.GetVariable("SetParametersProvider");
                    engine.Operations.Call(method, provider);
                }
            }
            catch (Exception ex)
            {
                exception = ex;
            }

        }

        #endregion

        #region WebPart Verbs

        public override WebPartVerbCollection Verbs
        {
            get
            {
                if (exception != null)
                    return base.Verbs;

                try
                {
                    if (engine!=null && engine.Scope.ContainsVariable("GetVerbs"))
                    {
                        object method = engine.Scope.GetVariable("GetVerbs");
                        return engine.Operations.Call(method) as WebPartVerbCollection;
                    }
                }
                catch (Exception ex)
                {
                    exception = ex;
                }

                return base.Verbs;
            }
        }

        #endregion

        public new void SetPersonalizationDirty()
        {
            base.SetPersonalizationDirty();
        }
    }
}
